package cn.kgc.vue.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.MD5;
import cn.kgc.vue.commons.QueryCondition;
import cn.kgc.vue.commons.ResponseResult;
import cn.kgc.vue.entity.Permission;
import cn.kgc.vue.entity.RolePers;
import cn.kgc.vue.entity.User;
import cn.kgc.vue.entity.UserRole;
import cn.kgc.vue.form.LoginForm;
import cn.kgc.vue.form.UserForm;
import cn.kgc.vue.mapper.*;
import cn.kgc.vue.service.UserService;
import cn.kgc.vue.utils.IpUtil;
import cn.kgc.vue.utils.JWTUtil;
import cn.kgc.vue.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mengshun
 * @description 针对表【sys_user】的数据库操作Service实现
 * @createDate 2024-04-09 08:54:15
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private JWTUtil jwtUtil;

    @Resource
    private DeptMapper deptMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RolePersMapper rolePersMapper;

    @Resource
    private PermissionMapper permissionMapper;


    @Override
    public ResponseResult login(LoginForm loginForm, HttpServletRequest request) {

        // 1. 判定验证码
        String uuid = loginForm.getUuid();
        String redisCode = stringRedisTemplate.opsForValue().get(uuid);
        String formCode = loginForm.getCode();

        if (StringUtils.isEmpty(redisCode)) {
            return ResponseResult.fail().message("验证码失效,请刷新重试");
        }

        if (!StringUtils.equals(redisCode, formCode)) {
            return ResponseResult.fail().message("验证码错误");
        }

        // 校验用户名
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername, loginForm.getUsername());
        User user = baseMapper.selectOne(lambda);

        if (ObjectUtils.isNull(user)) {
            throw new UnknownAccountException("用户名不存在");
        }

        // 校验用户的状态
        Integer state = user.getState();
        if (state == 0) {
            throw new LockedAccountException("用户被禁用");
        }


        // 校验密码      formPassword 明文  DBPassword 密文
        String formPassword = loginForm.getPassword();
        String DBPassword = user.getPassword();

        // shiro  MD5
        formPassword = new Md5Hash(formPassword, user.getSalt(), 1024).toHex();
        if (!StringUtils.equals(DBPassword, formPassword)) {
            throw new IncorrectCredentialsException("密码错误");
        }


        HashMap<String, Object> payload = new HashMap<>();
        payload.put("username", user.getUsername());
        payload.put("uid", user.getId());

        String token = jwtUtil.createToken(payload);

        // 生成token      token : ip    192.168,253.135    -> redis  token   192.168.253.136
        // 将token 缓存在redis  token:ip  防止token的盗用
        String key = MD5.create().digestHex16(token);
        String ip = IpUtil.getIp(request);
        stringRedisTemplate.opsForValue().set(key, ip, 7, TimeUnit.DAYS);
        String nickName = user.getNickName();


        return ResponseResult.success()
                .message("认证通过")
                .data("token", token)
                .data("nickName", nickName);
    }


    @Override
    public ResponseResult userPage(QueryCondition<User> queryCondition) {

        Integer page = queryCondition.getPage();
        Integer limit = queryCondition.getLimit();
        Page<User> userPage = new Page<>(page, limit);

        // 动态sql的处理  username   state  deptId
        String username = queryCondition.getSearchParams().getUsername();
        Integer deptId = queryCondition.getSearchParams().getDeptId();
        Integer state = queryCondition.getSearchParams().getState();

        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(StringUtils.isNotBlank(username), User::getUsername, username)
                .eq(ObjectUtils.isNotNull(deptId), User::getDeptId, deptId)
                .eq(ObjectUtils.isNotNull(state), User::getState, state)
                .orderByDesc(User::getCreateTime);

        baseMapper.selectPage(userPage, lambda);

        // 处理分页数据
        long total = userPage.getTotal();
        List<User> records = userPage.getRecords();
        //  User -> UserVO
        List<UserVO> collect = records.stream().map(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);

            // 部门名称
            Integer deptId1 = user.getDeptId();
            String deptName = deptMapper.selectById(deptId1).getDeptName();
            userVO.setDeptName(deptName);

            // 角色名称列表
            Integer uid = user.getId();
            LambdaQueryWrapper<UserRole> lambda1 = new QueryWrapper<UserRole>().lambda();
            lambda1.eq(UserRole::getUserId, uid);

            List<Integer> rids = userRoleMapper.selectList(lambda1).stream()
                    .map(ur -> ur.getRoleId())
                    .collect(Collectors.toList());

            List<String> roleNames = roleMapper.selectBatchIds(rids).stream()
                    .map(role -> role.getRoleCh())
                    .collect(Collectors.toList());

            userVO.setRoleNames(roleNames);

            return userVO;
        }).collect(Collectors.toList());


        return ResponseResult.success().data("total", total).data("tableData", collect);
    }

    @Override
    public ResponseResult addUser(UserForm userForm) {

        // 判定添加的用户名是否存在
        String username = userForm.getUsername();
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getUsername, username);
        User user = baseMapper.selectOne(lambda);
        if (ObjectUtils.isNotNull(user)) {
            return ResponseResult.fail().message("账号已被注册");
        }


        // user
        User usr = new User();
        BeanUtils.copyProperties(userForm, usr);
        // 设置默认密码    salt
        String defaultPassword = "111111";
        String salt = RandomUtil.randomString(8);
        String MD5Password = new Md5Hash(defaultPassword, salt, 1024).toHex();
        usr.setPassword(MD5Password);
        usr.setSalt(salt);

        baseMapper.insert(usr);

        Integer id = usr.getId();
        List<Integer> roleIds = userForm.getRoleId();
        // user_role
        roleIds.forEach(roleId -> {
            UserRole userRole = new UserRole();
            userRole.setRoleId(roleId);
            userRole.setUserId(id);
            userRoleMapper.insert(userRole);
        });

        return ResponseResult.success().message("添加成功");
    }

    @Override
    public ResponseResult getByUId(Integer id) {

        UserForm userForm = new UserForm();

        // 根据用户id  查询用户表
        User user = baseMapper.selectById(id);
        BeanUtils.copyProperties(user,userForm);

        // 根据用户id  查询用户角色关联表  sys_user_role
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId,id);

        List<Integer> collect = userRoleMapper.selectList(lambda)
                .stream().map(ur -> ur.getRoleId())
                .collect(Collectors.toList());

        userForm.setRoleId(collect);

        return ResponseResult.success().data("userInfo",userForm);
    }

    @Override
    public ResponseResult editUser(UserForm userForm) {

        // user   sys_user
        User user = new User();
        BeanUtils.copyProperties(userForm,user);
        baseMapper.updateById(user);

        // role   sys_user_role

        // 1.根据用户id  删除用户所有的角色
        Integer uid = userForm.getId();
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId,uid);
        userRoleMapper.delete(lambda);

        //2. 将用户最新的角色信息添加到数据库
        List<Integer> roleId = userForm.getRoleId();

        roleId.forEach(rid->{
            UserRole userRole = new UserRole(uid,rid);
            userRoleMapper.insert(userRole);
        });

        return ResponseResult.success().message("更新成功");
    }

    @Override
    public ResponseResult resetPassword(Integer id) {

        // 重新设置用户密码
        String defaultPassword = "111111";
        String salt = RandomUtil.randomString(8);
        String MD5Password = new Md5Hash(defaultPassword, salt, 1024).toHex();

        User user = new User();
        user.setId(id);
        user.setPassword(MD5Password);
        user.setSalt(salt);

        baseMapper.updateById(user);

        return ResponseResult.success().message("密码重置成功");
    }

    @Override
    public ResponseResult editState(Integer id, Integer state) {

        User user = new User();
        user.setId(id);
        user.setState(state);

        baseMapper.updateById(user);

        return ResponseResult.success().message("状态更新成功");
    }

    @Override
    public ResponseResult delete(List<Integer> uids) {

        // 删除用户表中的数据
        baseMapper.deleteBatchIds(uids);
        // 删除用户角色关联表中的数据
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.in(UserRole::getUserId,uids);

        userRoleMapper.delete(lambda);


        return ResponseResult.success().message("删除成功");
    }

    @Override
    public ResponseResult getPersonalInfo(HttpServletRequest request) {

        // 获取请求头中携带的token 解析用户信息
        String token = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(token).get("uid");

        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.eq(User::getId,uid)
                .select(User::getId,User::getNickName,User::getSex,User::getCity,User::getTel);

        User user = baseMapper.selectOne(lambda);

        return ResponseResult.success().data("personal",user);
    }

    @Override
    public ResponseResult editPersonalPwd(Map<String, String> pwdInfo, HttpServletRequest request) {


        // 根据请求头中的token 获取用户id
        String token = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(token).get("uid");

        // 根据用户id  查询用户信息
        User user = baseMapper.selectById(uid);
        String DBPassword = user.getPassword();
        String salt = user.getSalt();
        // 比较用户的旧密码是否正确   明文  加密
        String s = pwdInfo.get("old");
        String hex = new Md5Hash(s, salt, 1024).toHex();
        if (!StringUtils.equals(DBPassword,hex)){
            return ResponseResult.fail().message("原始密码不正确");
        }
        // 修改新密码    加密  随机盐
        String newPwd = pwdInfo.get("newPwd");
        newPwd = new Md5Hash(newPwd, salt, 1024).toHex();

        User usr= new User();
        usr.setId(uid);
        usr.setPassword(newPwd);
        baseMapper.updateById(usr);

        return ResponseResult.success().message("密码修改成功");
    }

    @Override
    public ResponseResult logout(HttpServletRequest request) {

        // 根据请求头中的token 获取用户id
        String token = request.getHeader("authorization");

        // 从redis中移除当前token
        String key = MD5.create().digestHex16(token);
        stringRedisTemplate.delete(key);

        return ResponseResult.success().message("安全退出");
    }

    @Override
    public ResponseResult userMenu(HttpServletRequest request) {

        // 根据 token  获取用户的权限
        String authorization = request.getHeader("authorization");
        Integer uid = (Integer) jwtUtil.getClaims(authorization).get("uid");

        // 根据用户id  查询用户角色id
        LambdaQueryWrapper<UserRole> lambda = new QueryWrapper<UserRole>().lambda();
        lambda.eq(UserRole::getUserId,uid);

        List<Integer> rids = userRoleMapper.selectList(lambda)
                .stream()
                .map(ur -> ur.getRoleId())
                .collect(Collectors.toList());

        // 根据用户角色id  查询权限id
        LambdaQueryWrapper<RolePers> lambda1 = new QueryWrapper<RolePers>().lambda();
        lambda1.in(RolePers::getRoleId,rids);

        Set<Integer> permissionIds = rolePersMapper.selectList(lambda1)
                .stream()
                .map(rp -> rp.getPerId())
                .collect(Collectors.toSet());

        // 根据权限id  查询权限具体信息   处理权限信息    排除按钮级别的权限
        List<Permission> permissions = permissionMapper.selectBatchIds(permissionIds)
                .stream()
                .filter(permission -> permission.getIsMenu() != 2)
                .collect(Collectors.toList());

        return ResponseResult.success().data("permissions",permissions);
    }
}




